﻿using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;

namespace NazTek.Utility
{
    /// <summary>
    /// Encapsulates application metadata.
    /// </summary>
    public sealed class ApplicationMetadata
    {
        /// <summary>
        /// Gets executing assembly name.
        /// </summary>
        public string AssemblyName { get; private set; }
        /// <summary>
        /// Gets product name.
        /// </summary>
        public string Product { get; private set; }
        /// <summary>
        /// Gets title.
        /// </summary>
        public string Title { get; private set; }
        /// <summary>
        /// Gets product description.
        /// </summary>
        public string Description { get; private set; }
        /// <summary>
        /// Gets product version.
        /// </summary>
        public Version Version { get; private set; }
        /// <summary>
        /// Extracts metadata from executing assembly.  Sets <see cref="AssemblyName"/>, <see cref="Product"/>, 
        /// <see cref="Title"/>, <see cref="Description"/>, and <see cref="Version"/>.
        /// </summary>
        public ApplicationMetadata()
        {
            AssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
            Version = Assembly.GetEntryAssembly().GetName().Version;

            var customAttributes = Assembly.GetExecutingAssembly().GetCustomAttributes();
            var attributes = customAttributes as Attribute[] ?? customAttributes.ToArray();

            Product = GetAttributeValue<AssemblyProductAttribute>(attributes, value => value.Product);
            Description = GetAttributeValue<AssemblyDescriptionAttribute>(attributes, value => value.Description);
            Title = GetAttributeValue<AssemblyTitleAttribute>(attributes, value => value.Title);
        }
        /// <summary>
        /// Gets the first non-null custom attribute value from
        /// <see cref="Description"/>, <see cref="Title"/>, <see cref="Product"/>, and <see cref="AssemblyName"/>.
        /// </summary>
        /// <returns>Deduced application name.</returns>
        public string GetApplicationName()
        {
            return Description ?? Title ?? Product ?? AssemblyName;
        }

        private static string GetAttributeValue<T>(IEnumerable<Attribute> attributes, Func<T, string> getValue) where T : class
        {
            var value = attributes.FirstOrDefault(a => a is T) as T;
            return value == null ? null : getValue(value);
        }
    }
}